Skip to content

fix(install): recognise junctions at skill-link paths#82

Merged
emp3thy merged 1 commit into
mainfrom
fix/installer-junction-skills
Jul 22, 2026
Merged

fix(install): recognise junctions at skill-link paths#82
emp3thy merged 1 commit into
mainfrom
fix/installer-junction-skills

Conversation

@emp3thy

@emp3thy emp3thy commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Deploying #81 crashed install_hooks on this machine: a junction (mklink /J) at ~/.claude/skills/better-memory-synthesize reports is_symlink() == False, so the installer fell into the real-directory branch and called shutil.rmtree, which refuses links ("Cannot call rmtree on a symbolic link"). The crash lands before the settings.json / .claude.json writes — a total install failure.

Junctions need no Developer Mode, making them the natural manual workaround for the installer's own symlink-privilege WARN — i.e. the crash targets exactly the locked-down-Windows users the fallback exists for.

Fix

  • Detect links with is_symlink() or os.path.isjunction(...).
  • Skip when the link already resolves to the source (this machine's case).
  • Otherwise remove the link itself: unlink(), os.rmdir fallback for dir junctions — never the target's contents.

Tests

  • New e2e test creates a real junction with mklink /J, runs the installer, asserts exit 0 + both configs written + junction untouched (skips where junctions can't be created).
  • tests/cli/test_install_hooks.py + tests/e2e/test_setup_sh.py: 44 passed.

🤖 Generated with Claude Code

A junction (mklink /J) at ~/.claude/skills/<name> reports is_symlink() ==
False, so the installer fell into the real-directory branch and called
shutil.rmtree, which refuses links outright — crashing install_hooks before
the JSON writes. Junctions are the natural workaround for the installer's
own "enable Developer Mode" warning (they need no privilege), so the crash
hits exactly the users the symlink fallback was written for.

Treat junctions like symlinks: skip when already pointing at the source,
otherwise remove the link itself (unlink, with os.rmdir fallback for dir
junctions) and never its target.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Claude BugBot Analysis

No bugs found in the changes. The fix correctly guards junction handling with os.path.isjunction (safe given the project's Python >=3.12 requirement and the function's cross-platform no-op behavior), and the fallback os.rmdir on unlink failure only removes the reparse point, not target contents.

No bugs were detected in this PR.

@emp3thy
emp3thy merged commit d1fe55d into main Jul 22, 2026
3 checks passed
@emp3thy
emp3thy deleted the fix/installer-junction-skills branch July 22, 2026 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant